#ifndef GRIDSERVER_H
#define GRIDSERVER_H

/*!
 * \file GridServer.h
 * \author thomas raynal
 * \version 2.0
 */


#include "GridTcpConnection.h"
#include "NewGridConnectionManager.h"
#include "Log.h"
#include <map>
#include <vector>
#include <time.h>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

/*! \namespace Network
 * 
 * Group client/server related classes. Offer API for handling both server and clients.
 */
namespace Network
{

/*! \class GridServer
* \brief Represent a server
* Message model must be specified
*/
template <class MessageRequest, class MessageResponse>
class GridServer 
{
public:

	tcp::acceptor acceptor;

    GridServer(asio::io_service& io_service,
		std::string address,
		int port,
		int connectionTimeout)
        : acceptor(io_service, tcp::endpoint(tcp::v4(), port)),
		t_(io_service),
		connection_manager_(),address_(address),
		connectionTimeout(connectionTimeout)
	{
		SetCheckConnections ();
	}

	/*!
    *  \brief Getter for the binded connection manager
    *
    */
	NewGridConnectionManager<MessageRequest,MessageResponse>* GetConnectionManager ()
	{
		return &connection_manager_;
	}

	/*!
    *  \brief Run the server
    *
    */
	void Start(BehaviorHandler<MessageRequest,MessageResponse>* h)
	{
		handler_ = h;
		StartAccept (h);
	}

	/*!
    *  \brief Stop the server
    *
    */
	void Stop ()
	{
		HandleStop();
	}

	~GridServer()
	{
		 Stop();
	}

private :

	NewGridConnectionManager<MessageRequest,MessageResponse> connection_manager_;
	BehaviorHandler<MessageRequest,MessageResponse>* handler_;
	std::string address_;
	int connectionTimeout;
	boost::asio::deadline_timer t_;

	void StartAccept (BehaviorHandler<MessageRequest,MessageResponse>* handler)
	{
	 boost::shared_ptr<GridTcpConnection<MessageRequest,MessageResponse>> connection=
			GridTcpConnection<MessageRequest,MessageResponse>::Create(acceptor.get_io_service(),handler_);

      acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));

	  acceptor.async_accept(connection->GetSocket(),boost::bind(&GridServer::HandleAccept, this, connection,asio::placeholders::error));
    }

    void HandleAccept(boost::shared_ptr<GridTcpConnection<MessageRequest,MessageResponse>> connection,
            const boost::system::error_code& error)
    {
        if (!error) 
		{
			connection_manager_.Start(connection);
			PrintLog("New connection registered");
			StartAccept(handler_);
        }
    }

	void SetCheckConnections()
	{
      t_.expires_from_now(boost::posix_time::seconds(connectionTimeout));
      t_.async_wait(boost::bind(&GridServer::HandleCheckConnections,this));	
	}

    void HandleCheckConnections()
	{
      connection_manager_.CheckAll();
      SetCheckConnections();
	}

	void HandleStop()
	{
	  acceptor.close();
	}
};
}
#endif